package cz.proks.easyhelpdesk.gwt.ui;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Widget;

import cz.proks.easyhelpdesk.api.model.Category;
import cz.proks.easyhelpdesk.api.model.Ticket;
import cz.proks.easyhelpdesk.api.model.User;
import cz.proks.easyhelpdesk.gwt.event.CancelEvent;
import cz.proks.easyhelpdesk.gwt.event.TicketReplyEvent;
import cz.proks.easyhelpdesk.gwt.event.TicketSaveEvent;
import cz.proks.easyhelpdesk.gwt.ui.composite.RestrictedHelpdeskComposite;
import cz.proks.easyhelpdesk.gwt.ui.layout.HelpdeskMainLayoutPanel;
import cz.proks.easyhelpdesk.gwt.ui.layout.IsMainLayoutPanel.ForHelpdesk;
import cz.proks.easyhelpdesk.gwt.ui.widget.TicketWidget;
import cz.proks.easyhelpdesk.gwt.ui.widget.TicketWidget.Mode;

public class ThreadViewImpl extends RestrictedHelpdeskComposite implements ThreadView, TicketReplyEvent.Handler, TicketSaveEvent.Handler, CancelEvent.Handler {

    private static ThreadViewImplUiBinder uiBinder = GWT.create(ThreadViewImplUiBinder.class);

    interface ThreadViewImplUiBinder extends UiBinder<Widget, ThreadViewImpl> {
    }

    @UiField HelpdeskMainLayoutPanel mainHelpdeskPanel;    
    @UiField FlowPanel ticketsPanel;   
    
    private Map<Long, Category> categoryMap;
    private Map<Long, User> memberMap;    
        
    private final Collection<Ticket> tickets = new LinkedList<Ticket>();
    private Presenter presenter;

    public ThreadViewImpl() {
        initWidget(uiBinder.createAndBindUi(this));
    }

    @Override
    protected void initWidget(Widget widget) {
        super.initWidget(widget);        
    }

    @Override
    public void setPresenter(Presenter presenter) {
        this.presenter = presenter;
    }

    @Override
    protected ForHelpdesk getRootPanel() {
        return mainHelpdeskPanel;
    }            

    @Override
    public void setUsers(Map<Long, User> memberMap) {
        this.memberMap = memberMap;
    }

    @Override
    public void setCategories(Map<Long, Category> categoryMap) {
        this.categoryMap = categoryMap;
    }

    public void setTickets(Ticket... tickets) {
        Collection<Ticket> ticketCollection = Arrays.asList(tickets);
        setTickets(ticketCollection);
    }
    
    public void setTickets(Collection<Ticket> tickets) {
        this.tickets.clear();
        this.ticketsPanel.clear();

        if (tickets != null) {
            this.tickets.addAll(tickets);
            Collection<TicketWidget> widgets = getTicketWidgets(this.tickets);
            for (TicketWidget widget : widgets)
                this.ticketsPanel.add(widget);
        }
    }                 
  
    public void onTicketReply(TicketReplyEvent event) {        
        final TicketWidget lastWidget = (TicketWidget) event.getSource();        
        final Widget replyWidget = ticketsPanel.getWidget(ticketsPanel.getWidgetCount() - 1);                               
        
        lastWidget.setMode(Mode.VIEW);
        replyWidget.setVisible(true);  
        
        onResize();
    }
    
    public void onTicketSave(TicketSaveEvent event) {
        presenter.saveReplyTicket(event.getTicket());
    }
    
    @Override
    public void onCancel(CancelEvent event) {
        TicketWidget replyWidget = (TicketWidget) event.getSource();
        TicketWidget lastThreadWidget = (TicketWidget) ticketsPanel.getWidget(ticketsPanel.getWidgetCount() - 2);
                       
        replyWidget.setVisible(false);
        lastThreadWidget.setMode(ticketsPanel.getWidgetCount() == 1 ? Mode.ONE_ONLY_VIEW : Mode.LAST_VIEW);
        
        onResize();
    }

    private Collection<TicketWidget> getTicketWidgets(Collection<Ticket> tickets) {
        Collection<TicketWidget> widgets = new LinkedList<TicketWidget>();
        
        boolean isOnlyOneTicket = tickets.size() == 1;
        boolean isFirst = true;
        Iterator<Ticket> iterator = tickets.iterator();
        
        TicketWidget widget = null;
        
        while (iterator.hasNext()) {                       
            Ticket ticket = iterator.next();            
            boolean isLast = !iterator.hasNext();
            
            if (isOnlyOneTicket)
                widget = getTicketWidget(ticket, Mode.ONE_ONLY_VIEW);
            
            else if (isFirst)
                widget = getTicketWidget(ticket, Mode.FIRST_VIEW);
            
            else if (isLast)
                widget = getTicketWidget(ticket, Mode.LAST_VIEW);
            
            else
                widget = getTicketWidget(ticket, Mode.VIEW);
            
            isFirst = false;
            widgets.add(widget);
        }
        
        widget = getReplyTicketWidget(tickets);        
        widget.setVisible(false);
        
        widgets.add(widget);
        
        return widgets;
    }
    
    private TicketWidget getReplyTicketWidget(Collection<Ticket> tickets) {
        Iterator<Ticket> iterator = tickets.iterator();
        Ticket ticket = iterator.hasNext() ? iterator.next() : new Ticket();
        TicketWidget widget = getTicketWidget(ticket, Mode.REPLY);
        
        widget.setDescription("");
        widget.addTicketSaveHandler(this);
        widget.addCancelHandler(this);
        
        return widget;
    }
    
    private TicketWidget getTicketWidget(Ticket ticket, Mode widgetMode) {
        User owner = memberMap.get(ticket.getOwnerId());
        TicketWidget widget = new TicketWidget(widgetMode);        
        
        widget.setCategories(categoryMap.get(ticket.getCategoryId()));
        widget.setCreatedDate(ticket.getCreated());
        widget.setUsernameLabel(owner.getName() + " " + owner.getSurname());
        widget.setSubject(ticket.getSubject());
        widget.setDescription(ticket.getDescription());   
        
        if (widgetMode == Mode.ONE_ONLY_VIEW || widgetMode == Mode.LAST_VIEW) {
            widget.addTicketReplyHandler(this);
        }
        
        return widget;
    }
    
    private Category getCategoryFrom(TicketWidget widget) {
        Category category = new Category();
        
        category.setId(widget.getCategoryId());
        category.setLabel(widget.getCategoryLabel());
        
        return category;
    }    
}
